package cc.opcol.iot.server.parser;

import cc.opcol.iot.server.domain.IoTEvent;
import cc.opcol.iot.server.domain.JsEventHandle;
import cc.opcol.iot.server.sdk.JSTimerManager;
import cc.opcol.iot.server.sdk.ScriptEngineHelper;
import cc.opcol.iot.server.server.IoTSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class JsSessionEventHandle implements SessionEventHandle {
    static Logger logger= LoggerFactory.getLogger(JsSessionEventHandle.class);

    ScriptEngineHelper scriptEngineHelper;

    @Autowired
    JSTimerManager jsTimerManager;

    private ConcurrentHashMap<String, List<JsEventHandle>> jsHandleMaps =new ConcurrentHashMap<>();

    public ScriptEngineHelper getScriptEngineHelper() {
        return scriptEngineHelper;
    }

    public void setScriptEngineHelper(ScriptEngineHelper scriptEngineHelper) {
        this.scriptEngineHelper = scriptEngineHelper;
    }

    public void addJsEvent(JsEventHandle jsEventHandle){
        List<JsEventHandle> list= jsHandleMaps.get(jsEventHandle.getKey());
        if(list==null){
            list=new ArrayList<>();
            jsHandleMaps.put(jsEventHandle.getKey(),list);
        }
        list.add(jsEventHandle);
        jsHandleMaps.put(jsEventHandle.getKey(),list);
    }

    @Override
    public void onReceived(StringBuffer dataBuf, IoTSession session) {
        List<JsEventHandle> jsEventHandles = jsHandleMaps.get(session.getDeviceType());
        if(jsEventHandles ==null){
            return;
        }
        for(JsEventHandle jsEventHandle : jsEventHandles){
            if(!jsEventHandle.getEventType().equals(IoTEvent.ON_SESSION_RECEIVED.name())){
                continue;
            }
            ScriptEngine jsEngine=scriptEngineHelper.createJsEngine();
            Invocable invocable=(Invocable)jsEngine;
            try {
                jsEngine.put("script_object",jsEventHandle);
                Map<String,Object> parameters=new HashMap<>();
                parameters.put("session",session);
                parameters.put("data",dataBuf);
                jsEngine.eval(jsEventHandle.getJsContent());
                invocable.invokeFunction("main",parameters);
            } catch (Exception e) {
                logger.error("",e);
            }
        }
    }

    @Override
    public void onActive(IoTSession session) {
        List<JsEventHandle> jsEventHandles = jsHandleMaps.get(session.getDeviceType());
        if(jsEventHandles ==null){
            return;
        }
        for(JsEventHandle jsEventHandle : jsEventHandles){
            if(!jsEventHandle.getEventType().equals(IoTEvent.ON_SESSION_ACTIVE.name())){
                continue;
            }
            ScriptEngine jsEngine=scriptEngineHelper.createJsEngine();
            jsEngine.put("script_object",jsEventHandle);
            Invocable invocable=(Invocable)jsEngine;
            try {
                Map<String,Object> parameters=new HashMap<>();
                parameters.put("session",session);
                jsEngine.eval(jsEventHandle.getJsContent());
                invocable.invokeFunction("main",parameters);
            } catch (Exception e) {
                logger.error("",e);
            }
        }
    }

    @Override
    public void onInActive(IoTSession session) {
        jsTimerManager.cancelTimer(session.getId());
    }

    public void removeJsEvent(Long id) {
        for(String key : jsHandleMaps.keySet()){
            boolean ok=false;
            List<JsEventHandle> jsEventHandles = jsHandleMaps.get(key);
            for(JsEventHandle jsEventHandle : jsEventHandles){
                if(jsEventHandle.get_id().longValue()==id.longValue()){
                    jsEventHandles.remove(jsEventHandle);
                    ok=true;
                    break;
                }
            }
            if(ok){
                break;
            }
        }
    }

    public void cleanJsEvent() {
        jsHandleMaps.clear();
    }

    public void checkTimer() {
        List<Long> jsIDList=jsTimerManager.listJsID();
        for(Long jsId:jsIDList){
            boolean existence=false;
            for(String key : jsHandleMaps.keySet()) {
                List<JsEventHandle> jsEventHandles = jsHandleMaps.get(key);
                for (JsEventHandle jsEventHandle : jsEventHandles) {
                    if(jsEventHandle.get_id()==jsId){
                        existence=true;
                        break;
                    }
                }
                if(existence){
                    break;
                }
            }
            if(!existence){
                jsTimerManager.cancelTimerByJSID(jsId);
            }
        }
    }
}
